------------------------------------------ LUA应用消息订阅/发布接口 ------------------------------------------
--[[ 
    参考文档：https://wiki.luatos.com/luaGuide/luaReference.html#os-date-format-time
    https://wiki.luatos.com/luaGuide/luatFramework_exts.html 
    1、在publish函数中，将”TEST”消息和参数插入messageQueue列表中
    此时messageQueue中为{{“TEST”,2;n=1}}
    2、在subscribe函数中判断消息和callback类型是否正确，如果正确则在subscribers中建立消息与回调函数之间的关系。
    此时subscribers[“TEST”][subCallBack] = true。表明TEST消息对应的回掉函数为subCallBack
    3、在dispatch()函数中，获得表头列表。
    local message = table.remove(messageQueue, 1)
    此时message为{“TEST”,2;n=1}
    找到该消息对应的回调函数或消息。将message中的参数传给回调函数。
    通过pairs遍历得到消息对应的回调函数或者任务。
    如果callback是函数，那么将publish时候的参数传给回调函数。
    如果callback是线程，那么唤醒该线程。
    以上只是单个消息举例，多个消息同理，因为每次循环都会将messageQueue的头部出队列，满足FIFO原则。
]]
-- 订阅者列表
local subscribers = {}
-- 内部消息队列
local messageQueue = {}
--- 订阅消息
-- @param id 消息id
-- @param callback 消息回调处理
-- @usage subscribe("NET_STATUS_IND", callback)
function subscribe(id, callback)
    if type(id) ~= "string" or
        (type(callback) ~= "function" and type(callback) ~= "thread") then
        print("warning: sys.subscribe invalid parameter", id, callback)
        return
    end
    if not subscribers[id] then subscribers[id] = {} end -- 如果没有重复消息
    subscribers[id][callback] = true -- 标记id和callback关系
end

--- 取消订阅消息
-- @param id 消息id
-- @param callback 消息回调处理
-- @usage unsubscribe("NET_STATUS_IND", callback)
function unsubscribe(id, callback)
    if type(id) ~= "string" or
        (type(callback) ~= "function" and type(callback) ~= "thread") then
        print("warning: sys.unsubscribe invalid parameter", id, callback)
        return
    end
    if subscribers[id] then subscribers[id][callback] = nil end -- 删除id和callback关系
end

--- 发布内部消息，存储在内部消息队列中
-- @param ... 可变参数，用户自定义
-- @return 无
-- @usage publish("NET_STATUS_IND")
function publish(...)
    table.insert(messageQueue, arg) -- 将不定参数插入队列中
end

-- 分发消息
local function dispatch()
    while true do
        if #messageQueue == 0 then -- 如果队列长度为  跳出循环
            break
        end
        local message = table.remove(messageQueue, 1) -- 获取队列的第一个
        if subscribers[message[1]] then -- 如果订消息存在
            for callback, _ in pairs(subscribers[message[1]]) do
                if type(callback) == "function" then
                    print("unpack", unpack(message, 2, #message))
                    callback(unpack(message, 2, #message)) -- 返回第二个到最后一个
                elseif type(callback) == "thread" then
                    coroutine.resume(callback, unpack(message))
                end
            end
        end
    end
end
subscribe("sys-publish", function(...) print('subscribers1:', ...) end)
subscribe("sys-publish", function(...) print('subscribers2:', ...) end)
subscribe("sys-publish", function(...) print('subscribers3:', ...) end)
publish("sys-publish", "hello", os.date("%Y-%m-%d %H:%M:%S"))
dispatch()
